package com.qf.listener;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qf.config.DelayedConfig;
import com.qf.constant.CacheConstants;
import com.qf.constant.RabbitMQConstants;
import com.qf.feign.CacheFegin;
import com.qf.model.StandardReport;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import java.util.Map;

/**
 * projectName: wokepase1
 *
 * @author: 强力
 * time: 2021/10/19 18:48
 * description:监听mq中的状态报告,推送给甲方项目
 */
@Component
@Slf4j
public class SmsReportListener {

    @Autowired
    private CacheFegin cacheFegin;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    //消息共发送5次,这个是发送的延时时间
    private  static  final Integer[] SMS_TTL={0,10000,30000,60000,300000};
    //监听mq中的状态报告队列,推送给甲方的项目
    @RabbitListener(queues = RabbitMQConstants.TOPIC_PUSH_SMS_REPORT)
    public  void  messageHandler(StandardReport standardReport, Channel channel, Message message) throws Exception{
        //1.获取客户端ID

        long clientID = standardReport.getClientID();

        //2.到redis中获取当前用户对象
        Map clientmap = cacheFegin.hMGet(CacheConstants.CACHE_PREFIX_CLIENT + clientID);

        //3.从用户对象中获取推送的目标服务器地址
        String receivestatusurl = String.valueOf(clientmap.get("receivestatusurl"));

        //4.获取用户是否需要返回状态报告状态0不返回 1返回
        String isreturnstatus = String.valueOf(clientmap.get("isreturnstatus"));

        //5.判断当前状态报告状态,如果是1,第一次推送
        if (!StringUtils.isEmpty(isreturnstatus)&&isreturnstatus.equals("1") ){
            //1设置用户接受状态报告的回调地址
            standardReport.setReceiveStatusUrl(receivestatusurl);
            //2设置推送次数,完成第一次推送
            standardReport.setSendCount(1);
            //3推送状态报告,并返回结果
            String result=null;
            result = sendReport(standardReport, result);
            //4判断推送报告返回的结果,如果为空,推送失败,报告进入延时队列
            if (StringUtils.isEmpty(result)){
                //5如果为空,进入延时队列
                sendDelayedMessage(standardReport);
                channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
            }else {
                //6如果用户接受到状态报告,返回success,确定用户接收到报告,停止推送
                log.info("[接口监听模块]推送报告:推送成功");
                isSuccess(standardReport,result);
            }
    }else {
            //6.如果状态报告的推送状态为0 ,则不推送
        log.info("[接口监听模块]推送报告:用户决定不推送,短信推送执行完毕");
        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
        }
    }

    /**
     *监听延时队列中的状态报告,都是曾经失败过得,在这重新推送
     */
    @RabbitListener(queues = DelayedConfig.DELAYED_QUEUE)
    public void delayedQueueHandler(StandardReport standardReport, Channel channel, Message message)throws Exception{
        //对发送次数进行计数
        standardReport.setSendCount(standardReport.getSendCount()+1);

        //封装请求头和请求体等参数
        String  result=null;
        result= sendReport(standardReport, result);
        //发送

        if (result == null) {
            return;
        }
        //判断是否发送成功
        isSuccess(standardReport,result);

        //返回ack
        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);

    }



    /**
     *将状态报告发送到mq的延时队列
     */
    private void sendDelayedMessage(StandardReport standardReport){
        log.info("[接口监听模块]推送报告:延时队列开始执行,standardReport={}",standardReport);
        //判断状态报告的发送次数,要小于5次
        if (standardReport.getSendCount()<= 5){
            rabbitTemplate.convertAndSend(DelayedConfig.DELAYED_EXCHANGE, "routingKey", standardReport, new MessagePostProcessor() {
                @Override
                public Message postProcessMessage(Message message) throws AmqpException {
                    //设置状态报告在队列中的延时时间  后面-1是因为从0开始计数
                    message.getMessageProperties().setDelay(SMS_TTL[standardReport.getSendCount()-1]);
                    return message;
                }
            });
        }
    }


    /**
     *发送状态报告
     * @param standardReport 发送对象
     * @param result 返回结果
     * @return
     */
    public String sendReport(StandardReport standardReport,String result){
        try {
            //1.封装请求头
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            //2.封装请求体,请求体中封装的是数据
            String jsonstr = objectMapper.writeValueAsString(standardReport);
            HttpEntity<String> httpEntity = new HttpEntity<>(jsonstr, headers);

            //3.发送请求
            result = restTemplate.postForObject(standardReport.getReceiveStatusUrl(), httpEntity, String.class);

            return result;
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            //4.如果发送出现异常,会进入到延时队列,继续等到发送
            log.info("[接口监听模块]推送报告:发送过程中异常,url={},standardReport={}",standardReport.getReceiveStatusUrl(),standardReport);
            //推送失败进入到延时队列
            sendDelayedMessage(standardReport);
            return null;
        }
    }

    /**
     * 状态报告推送成功
     * @param standardReport
     * @param result
     */
    private void  isSuccess(StandardReport standardReport,String result){
        //如果不成功
        if (!"SUCCESS".equalsIgnoreCase(result)){
            // 进入到延时队列
sendDelayedMessage(standardReport);
        }else {
            log.info("[接口监听模块]推送报告:推送成功");

        }
    }
}
